package summaries;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import sets.IFuzzySet;
import utils.Interval;

import norms.INorm;
import norms.TNorm;

import linguistic.Qualifier;
import linguistic.Quantifier;
import linguistic.Quantifier.QuantifierType;
import linguistic.Summarizer;

public class Summary {
	private Quantifier quantifier = null;
	private List<Summarizer> summarizers = new ArrayList<>();
	private List<Qualifier> qualifiers = new ArrayList<>();
	private List<Map<String, Double>> tuples;
	private Results results;
	private String subject = "meczach";
	/**
	 * Is at least one summarizer or qualifier build on interval-valued fuzzy set?
	 */
	private boolean isInterval = false;
	
	public Summary() {
		
	}
	
	public Summary(Summary summary) {
		// Copy quantifier
		quantifier = summary.getQuantifier();
		
		// Copy qualifiers
		for (int i = 0; i < summary.getQualifiers().size(); ++i) {
			qualifiers.add(summary.getQualifiers().get(i));
		}
		
		// Copy summarisers
		for (int i = 0; i < summary.getSummarizers().size(); ++i) {
			summarizers.add(summary.getSummarizers().get(i));
		}
	}
	
	public void addQuantifier(Quantifier quantifier) {
		this.quantifier = quantifier;
	}
	
	public void addSummarizer(Summarizer summarizer) {
		summarizers.add(summarizer);
		
		if (summarizer.getFuzzySet().getType() == IFuzzySet.Type.INTERVAL) {
			isInterval = true;
		}
	}
	
	public void addQualifier(Qualifier qualifier) {
		qualifiers.add(qualifier);
		
		if (qualifier.getFuzzySet().getType() == IFuzzySet.Type.INTERVAL) {
			isInterval = true;
		}
	}
	
	/**
	 * Put all tuples from database into this summary.
	 * @param tuples
	 */
	public void setTuples(List<Map<String, Double>> tuples) {
		this.tuples = tuples;
		
		// And automatically put tuples to all summarizers and qualifiers
		for (int i = 0; i < summarizers.size(); ++i) {
			summarizers.get(i).putTuples(tuples);
		}
		for (int i = 0; i < qualifiers.size(); ++i) {
			qualifiers.get(i).putTuples(tuples);
		}
	}
	
	public Quantifier getQuantifier() {
		return quantifier;
	}
	
	public List<Summarizer> getSummarizers() {
		return summarizers;
	}
	
	public List<Qualifier> getQualifiers() {
		return qualifiers;
	}
	
	public Results getResults() {
		return results;
	}
	
	
	private String generateSummaryText() {
		String summary = "";
		summary += quantifier.getName() + " " + subject + " ";
		if (qualifiers.size() > 0) {
			summary += "będący/mający ";
			for (Qualifier qualifier : qualifiers) {
				summary += qualifier.getName() + " i ";
			}
			summary = summary.substring(0, summary.length() - 2);
		}
		
		summary += "jest/ma ";
		for (Summarizer summarizer : summarizers) {
			summary += summarizer.getName() + " i ";
		}
		summary = summary.substring(0, summary.length() - 2);
		return summary;
	}
	
	public void show() {
		System.out.println(generateSummaryText());
	}
	
	public String getText() {
		return generateSummaryText();
	}
	
	
	public void qualityMeasures() {
		
		// BUGFIX!!	// somewhere else is a huge bug, and isInterval variable
		for (Summarizer summarizer : summarizers) {
			if (summarizer.getFuzzySet().getType() == IFuzzySet.Type.INTERVAL) {
				isInterval = true;
			}
		}
		for (Qualifier qualifier : qualifiers) {
			if (qualifier.getFuzzySet().getType() == IFuzzySet.Type.INTERVAL) {
				isInterval = true;
			}
		}
		// BUGIFX!!
		
		if (!isInterval) {
			double T1  = T1();
			double T2  = T2();
			double T3  = T3();
			double T4  = T4();
			double T5  = T5();
			double T6  = T6();//T6();
			double T7  = T7();//T7();
			double T8  = T8();
			double T9  = T9();
			double T10 = T10();
			double T11 = T11();
			double T = T(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
			
			Results results = new Results(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T, generateSummaryText());
			this.results = results;
		} else {
			Interval T1_interval  = T1_interval();
			Interval T2_interval  = T2_interval();
			Interval T3_interval  = T3_interval();
			Interval T4_interval  = T4_interval();
			double T5 = T5_interval();
			double T6 = T6_interval();
			double T7 = T7_interval();
			Interval T8_interval  = T8_interval();
			Interval T9_interval  = T9_interval();
			Interval T10_interval = T10_interval();
			double T11 = T11_interval();
			Interval T_interval   = T_interval();
			
			Results results = new Results(T1_interval, T2_interval, T3_interval, T4_interval, T5,
										T6, T7, T8_interval, T9_interval, T10_interval,
										T11, T_interval, generateSummaryText());
			this.results = results;
		}
	}
	
	private double T(double T1, double T2, double T3, double T4, double T5, double T6, double T7, double T8, double T9, double T10, double T11) {
		double T = 0.0;
		T = T1  * (1.0 / 11.1) + T2  * (1.0 / 11.1) + T3  * (1.0 / 11.1) + T4  * (1.0 / 11.1) + T5  * (1.0 / 11.1) +
			T6  * (1.0 / 11.1) + T7  * (1.0 / 11.1) + T8  * (1.0 / 11.1) + T9  * (1.0 / 11.1) + T10 * (1.0 / 11.1) +
			T11 * (1.0 / 11.1);
		return T;
	}
	
	/**
	 * Degree of truth
	 * @return
	 */
	private double T1() {
		// This is probably the most complex quality measure...
		//   in first step, method has to detect what kind of summary it is
		//		- type 1 only with summarizer(s)
		//		- type 2 with qualifier(s)
		
		double T = 0.0;
		double S = 0.0;
		double W = 0.0;
		double SW = 0.0;
		double r = 0.0;
		INorm norm = new TNorm();
		
		if (qualifiers.size() == 0) {
			// Type 1 only summarizer(s)
			for (Map<String, Double> tuple : tuples) {
				double s = 1.0;
				for (Summarizer summarizer : summarizers) {
					s = norm.min(s, summarizer.membershipValue(tuple));
				}
				S += s;
			}
			r = S;			
		} else {
			// Type 2 with qualifier(s)
			for (Map<String, Double> tuple : tuples) {
				//
				
				double s = 1.0;
				for (Summarizer summarizer : summarizers) {
					s = norm.min(s, summarizer.membershipValue(tuple));
				}
				
				double w = 1.0;
				for (Qualifier qualifier : qualifiers) {
					w = norm.min(w, qualifier.membershipValue(tuple));
				}
				W += w;
				SW += norm.min(s, w);
			}
			r = SW / W;
		}
		
		//System.out.println("r from T1 = " + r);	////////// <-------------------------------------------
		
		if (quantifier.getType() == Quantifier.QuantifierType.ABSOLUTE) {
			T = quantifier.membershipValue(r / 1.0);
		} else {
			T = quantifier.membershipValue(r / (double)tuples.size());
		}
		
		if (qualifiers.size() > 0) {
			T = quantifier.membershipValue(r);
		}
		
		return T;
	}
	
	
	/**
	 * Degree of imprecision
	 * @return
	 */
	private double T2() {
		double T = 0;
		
		for (int i = 0; i < summarizers.size(); ++i) {
			T += summarizers.get(i).getFuzzySet().in().toDouble();	// non-interval set
		}
		
		T = Math.pow(T, 1.0 / summarizers.size());
		
		return T;
	}
	
	/**
	 * Degree of covering (only for summaries with qualifiers)
	 * @return
	 */
	private double T3() {
		double T = 0.0;
		INorm norm = new TNorm();
		
		if (qualifiers.size() == 0) {
			T = 0.0;
		} else {
			double t = 0.0;
			double h = 0.0;
			for (Map<String, Double> tuple : tuples) {
				double s = 1.0;
				double w = 1.0;
				
				// Compute value of compound summariser
				for (int i = 0; i < summarizers.size(); ++i) {
					s = norm.min(s, summarizers.get(i).membershipValue(tuple));
				}
				
				// Compute value of compound qualifier
				for (int i = 0; i < qualifiers.size(); ++i) {
					w = norm.min(w, qualifiers.get(i).membershipValue(tuple));
				}
				
				if (s > 0.0 && w > 0.0) {
					t = t + 1.0;
				}
				
				if (w > 0.0) {
					h = h + 1.0;
				}
			}
			
			T = t / h;
		}
		
		return T;
	}
	
	/**
	 * Degree of appropriateness
	 * @return
	 */
	private double T4() {
		double T = 1.0;
		
		List<Double> r = new ArrayList<>();
		
		for (int i = 0; i < summarizers.size(); ++i) {
			double g = 0.0;
			for (Map<String, Double> tuple : tuples) {
				if (summarizers.get(i).membershipValue(tuple) > 0) {
					g = g + 1.0;
				}
			}
			g = g / tuples.size();
			r.add(g);
		}
		
		double T3 = T3();
		for (int i = 0; i < r.size(); ++i) {
			T *= r.get(i) - T3;
		}
		
		return Math.abs(T);
	}
	
	/**
	 * Length of summary
	 * @return
	 */
	private double T5() {
		double T = Math.pow(0.5, summarizers.size());
		T = T * 2;
		return T;
	}
	
	/**
	 * Degree of quantifier imprecision
	 * @return
	 */
	private double T6() {
		double lenQ = Math.abs(quantifier.getFuzzySet().getMembershipFunction().maxX() - quantifier.getFuzzySet().getMembershipFunction().minX());
		//double left = quantifier.getFuzzySet().getUniverseOfDiscorse().getMinBoundary();
		//double right = quantifier.getFuzzySet().getUniverseOfDiscorse().getMaxBoundary();
		//double lenX = right - left;
		double X = 0.0;
		if (quantifier.getType() == Quantifier.QuantifierType.ABSOLUTE) {
			X = tuples.size();
		} else {
			X = 1.0;
		}
		//System.out.println(lenQ + " " + X);
		return 1 - lenQ / X;
	}
	
	/**
	 * Degree of quantifier cardinality
	 * @return
	 */
	private double T7() {
		double X = 0.0;
		double Q = 0.0;
		if (quantifier.getType() == QuantifierType.ABSOLUTE) {
			X = tuples.size();
		} else {
			X = 1.0;
		}
		
		double universeMin = quantifier.getFuzzySet().getUniverseOfDiscorse().getMinBoundary();
		double universeMax = quantifier.getFuzzySet().getUniverseOfDiscorse().getMaxBoundary();
		
		double divader = 0;
		for (double i = universeMin; i <= universeMax; i += 0.01) {
			divader++;
			Q += quantifier.membershipValue(i);
		}
		Q = Q / divader;
		 
		/*double integral = 0.0;
		for (double i = universeMin; i <= universeMax - 0.001; i += 0.001) {
			integral += ( quantifier.membershipValue(i) + quantifier.membershipValue(i + 0.001) ) / 2; 
		}*/
		
		double T = 1.0 - (Q / X);
		//System.out.println("Q = " + Q + " X = " + X + " T = " + T);
		return T;
	}
	
	/**
	 * Degree of summariser cardinality
	 * @return
	 */
	private double T8() {
		double T = 1.0;
		double S = 0.0;
		double X = 0.0;
		
		for (Summarizer summarizer : summarizers) {
			S = summarizer.getFuzzySet().card().toDouble();		// non-interval set
			X = 0.0;
			X = tuples.size();
			//for (Map<String, Double> tuple : tuples) {
			//	X += tuple.get(summarizer.getColumn());
			//}			
			T *= S / X;
		}
		T = Math.pow(T, 1.0 / (double)summarizers.size());
		T = 1 - T;
		return T;
	}
	
	/**
	 * Degree of quantifier imprecision
	 * @return
	 */
	private double T9() {
		double T = 1.0;
		
		if (qualifiers.size() == 0) {
			T = 0.0;
		} else if (qualifiers.size() == 1) {
			T = qualifiers.get(0).getFuzzySet().in().toDouble();		// non-interval set
			T = 1 - T;
		} else {
			for (Qualifier qualifier : qualifiers) {
				T *= qualifier.getFuzzySet().in().toDouble();			// non-interval set
			}
			T = Math.pow(T, (1.0 / qualifiers.size()));
			T = 1 - T;
		}
		return T;
	}
	
	/**
	 * Degree of qualifier cardinality
	 * @return
	 */
	private double T10() {
		double T = 1.0;
		double W = 0.0;
		double X = 0.0;
		
		if (qualifiers.size() == 0) {
			T = 0.0;
		} else if (qualifiers.size() == 1) {
			W = qualifiers.get(0).getFuzzySet().card().toDouble();		// non-interval set
			X = 0.0;
			for (Map<String, Double> tuple : tuples) {
				X += tuple.get(qualifiers.get(0).getFuzzySet().getColumn());
			}
			
			T = W / X;
			T = 1 - T;
		} else {
			for (Qualifier qualifier : qualifiers) {
				W = qualifier.getFuzzySet().card().toDouble();		// non-interval set
				X = 0.0;
				for (Map<String, Double> tuple : tuples) {
					X += tuple.get(qualifier.getFuzzySet().getColumn());
				}
				T *= W / X;
			}
			T = Math.pow(T, 1.0 / qualifiers.size());
			T = 1 - T;
		}
		
		return T;
	}
	
	/**
	 * Length of qualifier
	 * @return
	 */
	private double T11() {
		double T = Math.pow(0.5, qualifiers.size());
		if (qualifiers.size() > 0) {
			T = T * 2;
			return T;
		} else {
			return 0.0;
		}
	}
	 
	// Quality Measures for interval sets
		private Interval T_interval() {
			return new Interval(0, 0);
	}
	
	/**
	 * Degree of truth for interval sets
	 * @return
	 */
	private Interval T1_interval() {
		Interval T1 = new Interval();
		INorm norm = new TNorm();
		
		double cardMin = 0.0;
		double cardMax = 0.0;
		
		double R1 = 0.0, R2 = 0.0, R3 = 0.0, R4 = 0.0;
		
		boolean isQualifierInterval = false;
		
		// 1st form of summary (summarizer(s) only)
		if (qualifiers.size() == 0) {
			for (Map<String, Double> tuple : tuples) {
				double sLower = 1.0;
				double sUpper = 1.0;
				// Two situations can happen, when summarizer will be build by type 1 fuzzy set or
				//	when summarizer will be build by intrval-valued fuzzy set.
				for (Summarizer summarizer : summarizers) {
					Interval memberships = null;
					if (summarizer.getFuzzySet().getType() == IFuzzySet.Type.INTERVAL) {
						memberships = summarizer.intervalMembershipValue(tuple);
					} else if (summarizer.getFuzzySet().getType() == IFuzzySet.Type.TYPE1) {
						memberships = new Interval(summarizer.membershipValue(tuple), summarizer.membershipValue(tuple));
					}
					
					sLower = norm.min(sLower, memberships.getX());
					sUpper = norm.min(sUpper, memberships.getY());
				}
				cardMin += sLower;
				cardMax += sUpper;
			}
		} else {
			// 2nd form of summary (summarizer(s) and qualifier(s))
			for (Qualifier qualifier : qualifiers) {
				if (qualifier.getFuzzySet().getType() == IFuzzySet.Type.INTERVAL) {
					isQualifierInterval = true;
				}
			}
			
			for (Map<String, Double> tuple : tuples) {
				double sLowerS = 1.0;
				double sUpperS = 1.0;
				for (Summarizer summarizer : summarizers) {
					Interval memberships = null;
					if (summarizer.getFuzzySet().getType() == IFuzzySet.Type.INTERVAL) {
						memberships = summarizer.intervalMembershipValue(tuple);
					} else if (summarizer.getFuzzySet().getType() == IFuzzySet.Type.TYPE1) {
						memberships = new Interval(summarizer.membershipValue(tuple), summarizer.membershipValue(tuple));
					}
					sLowerS = norm.min(sLowerS, memberships.getX());
					sUpperS = norm.min(sUpperS, memberships.getY());
				}
				
				double sLowerW = 1.0;
				double sUpperW = 1.0;
				double sW = 1.0;		// if any qualifier ain't build by interval-valued fuzzy set
				for (Qualifier qualifier : qualifiers) {
					Interval memberships = null;
					if (qualifier.getFuzzySet().getType() == IFuzzySet.Type.INTERVAL) {
						memberships = qualifier.intervalMembershipValue(tuple);
					} else if (qualifier.getFuzzySet().getType() == IFuzzySet.Type.TYPE1) {
						memberships = new Interval(qualifier.membershipValue(tuple), qualifier.membershipValue(tuple));
					}
					if (isQualifierInterval) {
						sLowerW = norm.min(sLowerW, memberships.getX());
						sUpperW = norm.min(sUpperW, memberships.getY());
					} else {
						sW = norm.min(sW, memberships.getX());
						//System.out.println(sW);
					}
				}
				
				// Create R values
				if (isQualifierInterval) {
					double r1 = 0.0;
					double r2 = 0.0;
					double r3 = 0.0;
					double r4 = 0.0;
					
					if (sLowerW > 0) {
						r1 = norm.min(sLowerS, sLowerW);
						r2 = norm.min(sUpperS, sLowerW);
					} else {
						r1 = 0.0;
						r2 = 0.0;
					}
					
					if (sUpperW > 0) {
						r3 = norm.min(sLowerS, sUpperW);
						r4 = norm.min(sUpperS, sUpperW);
					} else {
						r3 = 0.0;
						r4 = 0.0;
					}
					
					R1 += r1;
					R2 += r2;
					R3 += r3;
					R4 += r4;
					
				} else {
					double r1 = 0.0;	// card for lower (s1 intersection s2)
					double r2 = 0.0;	// card for upper (s1 intersection s2)
					
					if (sW > 0.0) {
						r1 = norm.min(sLowerS, sW) / sW;
						r2 = norm.min(sUpperW, sW) / sW;
					} else {
						r1 = 0;
						r2 = 0;
					}
					
					R1 += r1;
					R2 += r2;
				}
			}
			
			if (isQualifierInterval) {
				cardMin = 1.0;
				cardMin = Math.min(cardMin, R1);
				cardMin = Math.min(cardMin, R2);
				cardMin = Math.min(cardMin, R3);
				cardMin = Math.min(cardMin, R4);
				cardMax = 0.0;
				cardMax = Math.max(cardMax, R1);
				cardMax = Math.max(cardMax, R2);
				cardMax = Math.max(cardMax, R3);
				cardMax = Math.max(cardMax, R4);
			} else 
			{
				cardMin = 1.0;
				cardMin = Math.min(cardMin, R1);
				cardMin = Math.min(cardMin, R2);
				cardMax = 0.0;
				cardMax = Math.max(cardMax, R1);
				cardMax = Math.max(cardMax, R2);
			}
			
		}
		//System.out.println(R1 + " " + R2 + " " + R3 + " " + R4);
		//System.out.println(cardMin + " " + cardMax);
		double Tlower = 0;
		double Tupper = 0;
		if (quantifier.getType() == QuantifierType.ABSOLUTE) {
			Tlower = quantifier.membershipValue(cardMin / 1.0);
			Tupper = quantifier.membershipValue(cardMax / 1.0);
		} else {
			Tlower = quantifier.membershipValue(cardMin / (double)tuples.size());
			Tupper = quantifier.membershipValue(cardMax / (double)tuples.size());
		}
		
		if (Tlower < Tupper) {
			T1.setX(Tlower);
			T1.setY(Tupper);
		} else {
			T1.setX(Tupper);
			T1.setY(Tlower);
		}
		
		return T1;
	}
	
	private Interval T2_interval() {
		double Tlower = 0.0;
		double Tupper = 0.0;
		
		for (Summarizer summarizer : summarizers) {
			Interval in = summarizer.getFuzzySet().in();
			Tlower += in.getX();
			if (Double.isNaN(in.getY())) {
				Tupper += in.getX();
			} else {
				Tupper += in.getY();
			}
		}
		
		Tlower = Math.pow(Tlower, 1.0 / summarizers.size());
		Tupper = Math.pow(Tupper, 1.0 / summarizers.size());
		
		return new Interval(Tlower, Tupper);
	}
	
	private Interval T3_interval() {
		double Tlower = 0.0;
		double Tupper = 0.0;
		INorm norm = new TNorm();
		
		// Lets detect is any qualifier is build by interval-valued fuzzy set
		boolean isInterval = false;
		for (Qualifier qualifier : qualifiers) {
			if (qualifier.getFuzzySet().getType() == IFuzzySet.Type.INTERVAL) {
				isInterval = true;
			}
		}
		
		if (qualifiers.size() == 0) {
			Tlower = 0.0;
			Tupper = 0.0;
		} else {
			double tLower = 0.0;
			double tUpper = 0.0;
			double h = 0.0;
			double hLower = 0.0;
			double hUpper = 0.0;
			if (!isInterval) {
				for (Map<String, Double> tuple : tuples) {
					// Compute compound summarizer
					double sLower = 1.0;
					double sUpper = 1.0;
					for (Summarizer summarizer : summarizers) {
						Interval memberships = summarizer.intervalMembershipValue(tuple);
						sLower = norm.min(sLower, memberships.getX());
						sUpper = norm.min(sUpper, memberships.getY());
					}
					// Compute compound qualifier
					double w = 1.0;
					for (Qualifier qualifier : qualifiers) {
						w = norm.min(w, qualifier.membershipValue(tuple));
					}
					if (sLower > 0.0 && w > 0.0) {
						tLower = tLower + 1.0;
					}
					if (sUpper > 0.0 && w > 0.0) {
						tUpper = tUpper + 1.0;
					}
					if (w > 0.0) {
						h = h + 1.0;
					}
				}
				Tlower = tLower / h;
				Tupper = tUpper / h;
			} else {
				for (Map<String, Double> tuple : tuples) {
					double sLower = 1.0;
					double sUpper = 1.0;
					for (Summarizer summarizer : summarizers) {
						Interval memberships = null;
						if (summarizer.getFuzzySet().getType() == IFuzzySet.Type.INTERVAL) {
							memberships = summarizer.intervalMembershipValue(tuple);
						} else {
							memberships = new Interval(summarizer.membershipValue(tuple), summarizer.membershipValue(tuple));
						}
						sLower = norm.min(sLower, memberships.getX());
						sUpper = norm.min(sUpper, memberships.getY());
					}
					
					double wLower = 1.0;
					double wUpper = 1.0;
					for (Qualifier qualifier : qualifiers) {
						Interval memberships = null;
						if (qualifier.getFuzzySet().getType() == IFuzzySet.Type.INTERVAL) {
							memberships = qualifier.intervalMembershipValue(tuple);
						} else {
							memberships = new Interval(qualifier.membershipValue(tuple), qualifier.membershipValue(tuple));
						}
						wLower = norm.min(sLower, memberships.getX());
						wUpper = norm.min(sUpper, memberships.getY());
					}
					
					//if (sLower > 0 || sUpper > 0 || wLower > 0 || wUpper > 0) {
					//	System.out.println(sLower + " " + sUpper + " " + wLower + " " + wUpper);
					//}
					
					if (sLower > 0.0 && wLower > 0.0) {
						tLower = tLower + 1.0;
					}
					if (sUpper > 0.0 && wUpper > 0.0) {
						tUpper = tUpper + 1.0;
					}
					if (wLower > 0.0) {
						hLower = hLower + 1.0;
					}
					if (wUpper > 0.0) {
						hUpper = hUpper + 1.0;
					}
					//System.out.println(sLower + " " + wLower);
				}
				if (hLower > 0.0) {
					Tlower = tLower / hLower;
				} else {
					Tlower = 0.0;
				}
				if (hUpper > 0.0) {
					Tupper = tUpper / hUpper;
				} else {
					Tupper = 0.0;
				}
			}
		}
		
		return new Interval(Tlower, Tupper);
	}
	
	private Interval T4_interval() {
		double Tlower = 1.0;
		double Tupper = 1.0;
		
		List<Interval> r = new ArrayList<>();
		
		for (Summarizer summarizer : summarizers) {
			double gLower = 0.0;
			double gUpper = 0.0;
			for (Map<String, Double> tuple : tuples) {
				Interval memberships = null;
				if (summarizer.getFuzzySet().getType() == IFuzzySet.Type.INTERVAL) {
					memberships = summarizer.intervalMembershipValue(tuple);
				} else {
					memberships = new Interval(summarizer.membershipValue(tuple), summarizer.membershipValue(tuple));
				}
				if (memberships.getX() > 0.0) {
					gLower = gLower + 1;
				}
				if (memberships.getY() > 0.0) {
					gUpper = gUpper + 1;
				}
			}
			gLower = gLower / tuples.size();
			gUpper = gUpper / tuples.size();
			r.add(new Interval(gLower, gUpper));
		}
		
		Interval T3 = T3_interval();
		for (Interval i : r) {
			Tlower *= i.getX() - T3.getX();
			Tupper *= i.getY() - T3.getY();
		}
				
		return new Interval(Math.abs(Tlower), Math.abs(Tupper));
	}
	
	private double T5_interval() {
		double T5 = T5();
		return T5;
	}
	
	private double T6_interval() {
		return T6();
	}
	
	private double T7_interval() {
		return T7();
	}
	
	private Interval T8_interval() {
		double Tlower = 1.0;
		double Tupper = 1.0;
		double Slower = 0.0;
		double Supper = 0.0;
		double X = 0.0;
		
		for (Summarizer summarizer : summarizers) {
			//Slower = summarizer.getFuzzySet().card().toDouble();		// non-interval set
			Interval card = summarizer.getFuzzySet().card();
			Slower = card.getX();
			if (Double.isNaN(card.getY())) {
				Supper = card.getX();
			} else {
				Supper = card.getY();
			}
			X = tuples.size();
			
			Tlower *= Slower / X;
			Tupper *= Supper / X;
		}
		Tlower = Math.pow(Tlower, 1.0 / summarizers.size());
		Tlower = 1 - Tlower;
		Tupper = Math.pow(Tupper, 1.0 / summarizers.size());
		Tupper = 1 - Tupper;
		
		return new Interval(Tlower, Tupper);
	}
	
	private Interval T9_interval() {
		double Tlower = 1.0;
		double Tupper = 1.0;
		
		if (qualifiers.size() == 0) {
			Tlower = 0.0;
			Tupper = 0.0;
		} else {
			for (Qualifier qualifier : qualifiers) {
				Interval in = qualifier.getFuzzySet().in();
				Tlower *= in.getX();
				if (Double.isNaN(in.getY())) {
					Tupper *= in.getX();
				} else {
					Tupper *= in.getY();
				}
			}
			Tlower = Math.pow(Tlower, (1.0 / qualifiers.size()));
			Tupper = Math.pow(Tupper, (1.0 / qualifiers.size()));
			Tlower = 1 - Tlower;
			Tupper = 1 - Tupper;
		}
		
		return new Interval(Tlower, Tupper);
	}
	
	private Interval T10_interval() {
		double Tlower = 1.0;
		double Tupper = 1.0;
		double X = 0.0;
		double Wlower = 0.0;
		double Wupper = 0.0;
		
		if (qualifiers.size() == 0) {
			Tlower = 0.0;
			Tupper = 0.0;
		} else {
			for (Qualifier qualifier : qualifiers) {
				Interval card = qualifier.getFuzzySet().card();
				Wlower = card.getX();
				if (Double.isNaN(card.getY())) {
					Wupper = card.getX();
				} else {
					Wupper = card.getY();
				}
				X = tuples.size();
				
				Tlower *= Wlower / X;
				Tupper *= Wupper / X;
			}
		}
		Tlower = Math.pow(Tlower, 1.0 / qualifiers.size());
		Tlower = 1 - Tlower;
		Tupper = Math.pow(Tupper, 1.0 / qualifiers.size());
		Tupper = 1 - Tupper;
		
		return new Interval(Tlower, Tupper);
	}
	
	private double T11_interval() {
		double T11 = T11();
		return T11;
	}
	
}
